#ifndef __COROUTINE_FIBONACCI_H__
#define __COROUTINE_FIBONACCI_H__

#include <iostream>
#include <coroutine>

namespace coroutine_fibonacci
{
	// 在这个协程实现的版本里，fibonacci 函数是一个协程函数，每次执行到 co_yield a 时，就会暂停协程，
	// 把当前的斐波那契数 a 返回给调用者，并且保存当前的状态，包括 a 和 b 的值。等下次调用 move_next
	// 恢复协程时，又能接着上次的状态继续计算下一个数，就像你暂停看视频去干了别的事儿，回来还能接着之前的
	// 情节往下看。这样，咱们可以按需一个一个地获取斐波那契数，而不是一次性生成所有的数，大大节省了内存空间，
	// 提高了程序的运行效率。

	// 用于保存协程状态和数据的结构体
	struct FibonacciGenerator
	{
		struct promise_type
		{
			long long current;
			long long next;

			FibonacciGenerator get_return_object()
			{
				return FibonacciGenerator{
					std::coroutine_handle<promise_type>::from_promise(*this) };
			}

			std::suspend_always initial_suspend() { return {}; }
			std::suspend_always final_suspend() noexcept { return {}; }
			void unhandled_exception() { std::terminate(); }

			std::suspend_always yield_value(long long value)
			{
				current = value;
				return {};
			}

			void return_void() {}
		};

		//
		std::coroutine_handle<promise_type> coro;

		explicit FibonacciGenerator(std::coroutine_handle<promise_type> handle)
			: coro(handle)
		{
		}

		~FibonacciGenerator()
		{
			if (coro)
				coro.destroy();
		}

		FibonacciGenerator(const FibonacciGenerator&) = delete;
		FibonacciGenerator& operator=(const FibonacciGenerator&) = delete;

		FibonacciGenerator(FibonacciGenerator&& other) noexcept : coro(other.coro)
		{
			other.coro = nullptr;
		}

		FibonacciGenerator& operator=(FibonacciGenerator&& other) noexcept
		{
			if (this != &other)
			{
				coro = other.coro;
				other.coro = nullptr;
			}

			return *this;
		}

		bool move_next()
		{
			if (!coro.done())
			{
				coro.resume();
				return true;
			}
			return false;
		}

		long long current_value() const
		{
			return coro.promise().current;
		}
	};

	FibonacciGenerator fibonacci()
	{
		long long a = 0;
		long long b = 1;
		while (true)
		{
			co_yield a;
			long long next = a + b;
			a = b;
			b = next;
		}

		co_return;
	}

	void test(int num)
	{
		std::cout << "num: " << num << std::endl;

		FibonacciGenerator gen = fibonacci();
		for (int i = 0; i < num; ++i)
		{
			if (gen.move_next())
			{
				std::cout << "num: " << i << " -> " << gen.current_value() << std::endl;
			}
		}
		std::cout << std::endl;
	}
}


#endif